home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_oleo_1_2_2.lha / oleo-1.2.2 / regions.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  20KB  |  987 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "funcdef.h"
  20. #include <stdio.h>
  21. #include "sysdef.h"
  22. #include "global.h"
  23. #include "cell.h"
  24. #include "io-generic.h"
  25. #include "io-abstract.h"
  26. #include "io-utils.h"
  27. #include "lists.h"
  28. #include "ref.h"
  29. #include "regions.h"
  30. #include "io-term.h"
  31.  
  32. extern CELL *my_cell;
  33. extern int modified;
  34. extern CELLREF cur_row, cur_col;
  35.  
  36.  
  37. struct rng all_rng =
  38. {MIN_ROW, MIN_COL, MAX_ROW, MAX_COL};
  39.  
  40. /* Take a struct rng (R) and init its elements to R1 C1 R2 C2, making sure
  41.    they are put in in the right order.
  42.  */
  43. #if __STDC__
  44. void
  45. set_rng (struct rng *r, CELLREF r1, CELLREF c1, CELLREF r2, CELLREF c2)
  46. #else
  47. void
  48. set_rng (r, r1, c1, r2, c2)
  49.      struct rng *r;
  50.      CELLREF r1;
  51.      CELLREF c1;
  52.      CELLREF r2;
  53.      CELLREF c2;
  54. #endif
  55. {
  56.   if (r1 <= r2)
  57.     {
  58.       r->lr = r1;
  59.       r->hr = r2;
  60.     }
  61.   else
  62.     {
  63.       r->lr = r2;
  64.       r->hr = r1;
  65.     }
  66.   if (c1 <= c2)
  67.     {
  68.       r->lc = c1;
  69.       r->hc = c2;
  70.     }
  71.   else
  72.     {
  73.       r->lc = c2;
  74.       r->hc = c1;
  75.     }
  76. }
  77.  
  78. /* Flush all the cells in a region */
  79. void
  80. delete_region (where)
  81.      struct rng *where;
  82. {
  83.   CELLREF rr, cc;
  84.   CELL *pp;
  85.  
  86.   modified = 1;
  87.  
  88.   find_cells_in_range (where);
  89.   while (pp = next_row_col_in_range (&rr, &cc))
  90.     {
  91.       if (!pp->cell_formula && !GET_TYP (pp))
  92.     {
  93.       pp->cell_flags = 0;
  94.       pp->cell_font = 0;
  95.       continue;
  96.     }
  97.       cur_row = rr;
  98.       cur_col = cc;
  99.       my_cell = pp;
  100.       flush_old_value ();
  101.       pp->cell_formula = 0;
  102.       pp->cell_flags = 0;
  103.       pp->cell_font = 0;
  104.       push_refs (pp->cell_refs_from);
  105.       io_pr_cell (rr, cc, pp);
  106.     }
  107.   my_cell = 0;
  108. }
  109.  
  110. /* Turn on/off the locked bits in a region */
  111. void
  112. lock_region (where, locked)
  113.      struct rng *where;
  114.      int locked;
  115. {
  116.   CELL *cp;
  117.  
  118.   modified = 1;
  119.   make_cells_in_range (where);
  120.   while (cp = next_cell_in_range ())
  121.     SET_LCK (cp, locked);
  122. }
  123.  
  124. void
  125. format_region (where, fmt, just)
  126.      struct rng *where;
  127.      int fmt;
  128.      int just;
  129. {
  130.   CELL *cp;
  131.   CELLREF rr, cc;
  132.  
  133.   modified = 1;
  134.   make_cells_in_range (where);
  135.   while (cp = next_row_col_in_range (&rr, &cc))
  136.     {
  137.       if (fmt != -1)
  138.     SET_FMT (cp, fmt);
  139.       if (just != -1)
  140.     SET_JST (cp, just);
  141.       io_pr_cell (rr, cc, cp);
  142.     }
  143. }
  144.  
  145. unsigned short print_width;
  146.  
  147. void
  148. print_region (fp, print)
  149.      FILE *fp;
  150.      struct rng *print;
  151. {
  152.   CELLREF rr, cc;
  153.   CELL *cp;
  154.   char *ptr;
  155.   int w;
  156.   int j;
  157.   int lenstr;
  158.   int spaces;
  159.   CELLREF c_lo, c_hi;
  160.  
  161.   extern int default_jst, default_fmt;
  162.  
  163.   for (c_lo = print->lc, c_hi = 0; c_hi != print->hc; c_lo = c_hi + 1)
  164.     {
  165.       w = 0;
  166.       for (w = get_width (cc = c_lo); w <= print_width && cc <= print->hc; w += get_width (++cc))
  167.     ;
  168.       if (cc != c_lo)
  169.     --cc;
  170.       c_hi = cc;
  171.  
  172.       for (rr = print->lr; rr <= print->hr; rr++)
  173.     {
  174.       spaces = 0;
  175.       for (cc = c_lo; cc <= c_hi; cc++)
  176.         {
  177.           w = get_width (cc);
  178.           if (!w)
  179.         continue;
  180.           cp = find_cell (rr, cc);
  181.           if (!cp || !GET_TYP (cp))
  182.         {
  183.           spaces += w;
  184.           continue;
  185.         }
  186.           ptr = print_cell (cp);
  187.           lenstr = strlen (ptr);
  188.           if (lenstr == 0)
  189.         {
  190.           spaces += w;
  191.           continue;
  192.         }
  193.           if (spaces)
  194.         {
  195.           fprintf (fp, "%*s", spaces, "");
  196.           spaces = 0;
  197.         }
  198.           j = GET_JST (cp);
  199.           if (j == JST_DEF)
  200.         j = default_jst;
  201.           if (lenstr <= w - 1)
  202.         {
  203.           if (j == JST_LFT)
  204.             {
  205.               fprintf (fp, "%s", ptr);
  206.               spaces = w - lenstr;
  207.             }
  208.           else if (j == JST_RGT)
  209.             {
  210.               fprintf (fp, "%*s", w - 1, ptr);
  211.               spaces = 1;
  212.             }
  213.           else if (j == JST_CNT)
  214.             {
  215.               w = (w - 1) - lenstr;
  216.               fprintf (fp, "%*s", w / 2 + lenstr, ptr);
  217.               spaces = (w + 3) / 2;
  218.             }
  219. #ifdef TEST
  220.           else
  221.             {
  222.               panic ("What just %d", j);
  223.             }
  224. #endif
  225.         }
  226.           else
  227.         {
  228.           CELLREF ccc = cc;
  229.           CELL *ccp;
  230.           int tmp_wid;
  231.           unsigned short ww;
  232.  
  233.           for (ww = w;; tmp_wid = get_width (ccc), w += tmp_wid, spaces -= tmp_wid)
  234.             {
  235.               if (lenstr < w - 1)
  236.             break;
  237.               if (++ccc > c_hi)
  238.             break;
  239.               ccp = find_cell (rr, ccc);
  240.               if (!ccp || !GET_TYP (ccp) || GET_FMT (ccp) == FMT_HID)
  241.             continue;
  242.               if (GET_FMT (ccp) == FMT_DEF && default_fmt == FMT_HID)
  243.             continue;
  244.               break;
  245.             }
  246.           if (lenstr > w - 1)
  247.             {
  248.               if (GET_TYP (cp) == TYP_FLT)
  249.             {
  250.               ptr = adjust_prc (ptr, cp, w - 1, ww - 1, j);
  251.               lenstr = strlen (ptr);
  252.             }
  253.               else if (GET_TYP (cp) == TYP_INT)
  254.             {
  255.               ptr = numb_oflo;
  256.               lenstr = 80;
  257.             }
  258.               fprintf (fp, "%.*s", w - 1, ptr);
  259.               if (lenstr < w)
  260.             spaces += w - lenstr;
  261.               else
  262.             spaces++;
  263.             }
  264.           else
  265.             {
  266.               fprintf (fp, "%s", ptr);
  267.               spaces += w - lenstr;
  268.             }
  269.         }
  270.         }
  271.       (void) putc ('\n', fp);
  272.     }
  273.     }
  274. }
  275.  
  276.  
  277. /*
  278.    Set up regions for the move/copy functions.  This deals with default
  279.    sizing of the target region, regions that don't fit, etc.
  280.  
  281.    This returns
  282.     -1 if the regions overlap
  283.     0 if there is a *real* error
  284.     1 if the target is a multiple of the source
  285.     2 if everything is OK.
  286.  */
  287.  
  288. static int
  289. set_to_region (fm, to)
  290.      struct rng *fm;
  291.      struct rng *to;
  292. {
  293.   /* Delta {row,col} {from,to} */
  294.   int drf, dcf;
  295.   int drt, dct;
  296.   int ret = 2;
  297.  
  298.   drf = fm->hr - fm->lr;
  299.   drt = to->hr - to->lr;
  300.   if (drt == 0)
  301.     {
  302.       if (to->lr > MAX_ROW - drf)
  303.     {
  304.       io_error_msg ("The range won't fit this far down!");
  305.       return 0;
  306.     }
  307.       to->hr = to->lr + drf;
  308.     }
  309.   else if (drf != drt)
  310.     {
  311.       if ((drt + 1) % (drf + 1) == 0)
  312.     ret = 1;
  313.       else
  314.     {
  315.       io_error_msg ("Rows %u:%u and %u:%u don't fit", fm->lr, fm->hr, to->lr, to->hr);
  316.       return 0;
  317.     }
  318.     }
  319.   dcf = fm->hc - fm->lc;
  320.   dct = to->hc - to->lc;
  321.   if (dct == 0)
  322.     {
  323.       if (to->lc > MAX_COL - dcf)
  324.     {
  325.       io_error_msg ("The range won't fit this far over!");
  326.       return 0;
  327.     }
  328.       to->hc = to->lc + dcf;
  329.     }
  330.   else if (dcf != dct)
  331.     {
  332.       if ((dct + 1) % (dcf + 1) == 0)
  333.     ret = 1;
  334.       else
  335.     {
  336.       io_error_msg ("Cols %u:%u and %u:%u don't fit", fm->lc, fm->hc, to->lc, to->hc);
  337.       return 0;
  338.     }
  339.     }
  340.  
  341.   if (fm->lr == to->lr && fm->lc == to->lc)
  342.     {
  343.       io_error_msg ("Regions are in the same place");
  344.       return 0;
  345.     }
  346.  
  347.   if (((fm->lr <= to->lr && to->lr <= fm->hr) || (fm->lr <= to->hr && to->hr <= fm->hr))
  348.       && ((fm->lc <= to->lc && to->lc <= fm->hc) || (fm->lc <= to->hc && to->hc <= fm->hc)))
  349.     return -1;
  350.   modified = 1;
  351.   return ret;
  352. }
  353.  
  354. /* This is only complicated because it must deal with overlap, and it wants
  355.    to be smart about copying empty space. . .
  356.  */
  357. void
  358. move_region (fm, to)
  359.      struct rng *fm;
  360.      struct rng *to;
  361. {
  362.   /* Delta {row,col} */
  363.   int dr, dc;
  364.   int nr, nc;
  365.   int ov, dn;
  366.   struct rng del_to_1, del_to_2;
  367.   int do_2, dirs[2];
  368.   int maxr, maxc;
  369.   CELLREF cmax, rmax;
  370.   int cdmax, rdmax;
  371.   int ret = 0;
  372.  
  373.   switch (set_to_region (fm, to))
  374.     {
  375.     case 0:
  376.       return;
  377.  
  378.     case 1:
  379.       io_error_msg ("Can't move source to multiple targets");
  380.       return;
  381.  
  382.     case 2:
  383.       del_to_1 = *to;
  384.  
  385.       do_2 = 0;
  386.       dirs[0] = 1;
  387.       dirs[1] = 1;
  388.  
  389.       /* del_fm_1= *fm; */
  390.       break;
  391.  
  392.     default:
  393.       /* They overlap.  There are eight ways that
  394.            they can overlap.  */
  395.       if (to->lc == fm->lc && to->lr < fm->lr)
  396.     {
  397.       /* State 1:  'from' on bottom */
  398.       del_to_1.lr = to->lr;
  399.       del_to_1.lc = to->lc;
  400.       del_to_1.hr = fm->lr - 1;
  401.       del_to_1.hc = to->hc;
  402.  
  403.       do_2 = 0;
  404.       dirs[0] = 1;
  405.       dirs[1] = 1;
  406.  
  407.       /* del_fm_1.lr=to->hr+1;    del_fm_1.lc=fm->lc;
  408.             del_fm_1.hr=fm->hr;    del_fm_1.hc=fm->hc; */
  409.     }
  410.       else if (to->lc == fm->lc)
  411.     {
  412.       /* State 2: 'from' on top */
  413.       del_to_1.lr = fm->hr + 1;
  414.       del_to_1.lc = to->lc;
  415.       del_to_1.hr = to->hr;
  416.       del_to_1.hc = to->hc;
  417.  
  418.       do_2 = 0;
  419.       dirs[0] = -1;
  420.       dirs[1] = 1;
  421.  
  422.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=fm->lc;
  423.             del_fm_1.hr=to->lr-1;    del_fm_1.hc=fm->hc; */
  424.     }
  425.       else if (to->lr == fm->lr && to->lc < fm->lc)
  426.     {
  427.       /* State 3: 'from' on right */
  428.       del_to_1.lr = to->lr;
  429.       del_to_1.lc = to->lc;
  430.       del_to_1.hr = to->hr;
  431.       del_to_1.hc = fm->lc - 1;
  432.  
  433.       do_2 = 0;
  434.       dirs[0] = 1;
  435.       dirs[1] = 1;
  436.  
  437.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=to->hc+1;
  438.             del_fm_1.hr=fm->hr;    del_fm_1.hc=fm->hc; */
  439.     }
  440.       else if (to->lr == fm->lr)
  441.     {
  442.       /* State 4: 'from' on left */
  443.       del_to_1.lr = to->lr;
  444.       del_to_1.lc = fm->hc + 1;
  445.       del_to_1.hr = to->hr;
  446.       del_to_1.hc = to->hc;
  447.  
  448.       do_2 = 0;
  449.       dirs[0] = 1;
  450.       dirs[1] = -1;
  451.  
  452.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=fm->lc;
  453.             del_fm_1.hr=fm->hr;    del_fm_1.hc=to->lc-1; */
  454.     }
  455.       else if (fm->lr < to->lr && fm->lc < to->lc)
  456.     {
  457.       /* State 5: From on topleft */
  458.  
  459.       del_to_1.lr = to->lr;
  460.       del_to_1.lc = fm->hc + 1;
  461.       del_to_1.hr = fm->hr;
  462.       del_to_1.hc = to->hc;
  463.  
  464.       del_to_2.lr = fm->hr + 1;
  465.       del_to_2.lc = to->lc;
  466.       del_to_2.hr = to->hr;
  467.       del_to_2.hc = to->hc;
  468.  
  469.       do_2 = 1;
  470.       dirs[0] = -1;
  471.       dirs[1] = -1;
  472.  
  473.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=fm->lc;
  474.             del_fm_1.hr=to->lr-1;    del_fm_1.hc=fm->hc;
  475.  
  476.             del_fm_2.lr=to->lr;    del_fm_2.lc=fm->lc;
  477.             del_fm_2.hr=fm->hr;    del_fm_2.hc=to->lc-1; */
  478.     }
  479.       else if (fm->lr < to->lr)
  480.     {
  481.       /* State 6: 'from' on topright */
  482.       del_to_1.lr = to->lr;
  483.       del_to_1.lc = to->lc;
  484.       del_to_1.hr = fm->hr;
  485.       del_to_1.hc = fm->lc - 1;
  486.  
  487.       del_to_2.lr = fm->hr + 1;
  488.       del_to_2.lc = to->lc;
  489.       del_to_2.hr = to->hr;
  490.       del_to_2.hc = to->hc;
  491.  
  492.       do_2 = 1;
  493.       dirs[0] = -1;
  494.       dirs[1] = 1;
  495.  
  496.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=fm->lc;
  497.             del_fm_1.hr=to->lr-1;    del_fm_1.hc=fm->hc;
  498.  
  499.             del_fm_2.lr=to->lr;    del_fm_2.lc=to->hc+1;
  500.             del_fm_2.hr=fm->hr;    del_fm_2.hc=fm->hc; */
  501.     }
  502.       else if (fm->lc < to->lc)
  503.     {
  504.       /* State 7: 'from on bottomleft */
  505.       del_to_1.lr = to->lr;
  506.       del_to_1.lc = to->lc;
  507.       del_to_1.hr = fm->lr - 1;
  508.       del_to_1.hc = to->hc;
  509.  
  510.       del_to_2.lr = fm->lr;
  511.       del_to_2.lc = fm->hc;
  512.       del_to_2.hr = to->hr;
  513.       del_to_2.hc = to->hc;
  514.  
  515.       do_2 = 1;
  516.       dirs[0] = 1;
  517.       dirs[1] = -1;
  518.  
  519.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=fm->lc;
  520.             del_fm_1.hr=to->hr;    del_fm_1.hc=to->lc-1;
  521.  
  522.             del_fm_2.lr=to->hr+1;    del_fm_2.lc=fm->lc;
  523.             del_fm_2.hr=to->hr+1;    del_fm_2.hc=to->lc-1; */
  524.     }
  525.       else
  526.     {
  527.       /* State 8: 'from' on bottomright */
  528.       del_to_1.lr = to->lr;
  529.       del_to_1.lc = to->lc;
  530.       del_to_1.hr = fm->lr - 1;
  531.       del_to_1.hc = to->hc;
  532.  
  533.       del_to_2.lr = fm->lr;
  534.       del_to_2.lc = to->lc;
  535.       del_to_2.hr = to->hr;
  536.       del_to_2.hc = fm->lc - 1;
  537.  
  538.       do_2 = 1;
  539.       dirs[0] = 1;
  540.       dirs[1] = 1;
  541.  
  542.       /* del_fm_1.lr=fm->lr;    del_fm_1.lc=to->hc+1;
  543.             del_fm_1.hr=to->hr;    del_fm_1.hc=fm->hc;
  544.  
  545.             del_fm_2.lr=to->hr+1;    del_fm_2.lc=fm->lc;
  546.             del_fm_2.hr=fm->hr;    del_fm_2.hc=fm->hc; */
  547.     }
  548.     }
  549.   dn = to->hr - fm->hr;
  550.   ov = to->hc - fm->hc;
  551.  
  552.   dr = fm->hr - fm->lr;
  553.   dc = fm->hc - fm->lc;
  554.  
  555.   delete_region (&del_to_1);
  556.   if (do_2)
  557.     delete_region (&del_to_2);
  558.  
  559.   if (to->lr == MIN_ROW && to->hr == MAX_ROW)
  560.     {
  561.       shift_widths (ov, fm->lc, fm->hc);
  562.       ret = 1;
  563.     }
  564.  
  565.   shift_outside (fm, dn, ov);
  566.  
  567.   rmax = highest_row ();
  568.   if (rmax < fm->lr)
  569.     rdmax = -1;
  570.   else if (rmax > fm->hr)
  571.     rdmax = dr;
  572.   else
  573.     rdmax = rmax - fm->lr;
  574.   nr = (dirs[0] > 0) ? 0 : rdmax;
  575.   maxr = (dirs[0] > 0) ? rdmax + 1 : -1;
  576.   for (; nr != maxr; nr += dirs[0])
  577.     {
  578.       cmax = max_col (fm->lr + nr);
  579.       if (cmax < fm->lc)
  580.     cdmax = -1;
  581.       else if (cmax > fm->hc)
  582.     cdmax = dc;
  583.       else
  584.     {
  585.       cdmax = cmax - fm->lc;
  586.     }
  587.       nc = (dirs[1] > 0) ? 0 : cdmax;
  588.       maxc = (dirs[1] > 0) ? cdmax + 1 : -1;
  589.       for (; nc != maxc; nc += dirs[1])
  590.     {
  591.       CELLREF rf, cf, rt, ct;
  592.       CELL *cpf;
  593.  
  594.       rf = fm->lr + nr;
  595.       cf = fm->lc + nc;
  596.       rt = to->lr + nr;
  597.       ct = to->lc + nc;
  598.  
  599.       cpf = find_cell (rf, cf);
  600.       cur_row = rt;
  601.       cur_col = ct;
  602.       my_cell = find_cell (cur_row, cur_col);
  603.       if ((!cpf
  604.            || (!cpf->cell_font && !cpf->cell_flags && !cpf->cell_formula))
  605.           && !my_cell)
  606.         continue;
  607.  
  608.       if (!cpf)
  609.         {
  610.           my_cell->cell_flags = 0;
  611.           my_cell->cell_font = 0;
  612.           my_cell->cell_refs_to = 0;
  613.           my_cell->cell_formula = 0;
  614.           my_cell->cell_cycle = 0;
  615.           my_cell = 0;
  616.           continue;
  617.         }
  618.       if (!my_cell)
  619.         {
  620.           my_cell = find_or_make_cell (cur_row, cur_col);
  621.           cpf = find_cell (rf, cf);
  622.         }
  623.       else
  624.         flush_old_value ();
  625.  
  626.       my_cell->cell_flags = cpf->cell_flags;
  627.       my_cell->cell_font = cpf->cell_font;
  628.       my_cell->cell_refs_to = cpf->cell_refs_to;
  629.       my_cell->cell_formula = cpf->cell_formula;
  630.       my_cell->cell_cycle = cpf->cell_cycle;
  631.       my_cell->c_z = cpf->c_z;
  632.  
  633.       cpf->cell_flags = 0;
  634.       cpf->cell_font = 0;
  635.       cpf->cell_refs_to = 0;
  636.       cpf->cell_formula = 0;
  637.       cpf->cell_cycle = 0;
  638.  
  639.       push_cell (cur_row, cur_col);
  640.  
  641.       if (!ret)
  642.         {
  643.           if (cpf)
  644.         io_pr_cell (rf, cf, cpf);
  645.           if (my_cell)
  646.         io_pr_cell (rt, ct, my_cell);
  647.         }
  648.       my_cell = 0;
  649.     }
  650.     }
  651.   return;
  652. }
  653.  
  654. void
  655. copy_region (fm, to)
  656.      struct rng *fm;
  657.      struct rng *to;
  658. {
  659.   CELLREF rf, rt, cf, ct;
  660.  
  661.   if (set_to_region (fm, to) < 1)
  662.     return;
  663.  
  664.   for (rf = fm->lr, rt = to->lr; (rt > 0) && (rt <= to->hr); rt++, rf++)
  665.     {
  666.       for (cf = fm->lc, ct = to->lc; (ct > 0) && (ct <= to->hc); ct++, cf++)
  667.     {
  668.       copy_cell (rf, cf, rt, ct);
  669.  
  670.       if (cf == fm->hc)
  671.         cf = fm->lc - 1;
  672.     }
  673.       if (rf == fm->hr)
  674.     rf = fm->lr - 1;
  675.     }
  676. }
  677.  
  678. void
  679. copy_values_region (fm, to)
  680.      struct rng *fm;
  681.      struct rng *to;
  682. {
  683.   CELLREF rf, rt, cf, ct;
  684.   union vals dummy;
  685.   CELL *cpf;
  686.  
  687.   if (set_to_region (fm, to) < 1)
  688.     return;
  689.  
  690.   for (rf = fm->lr, rt = to->lr; rt <= to->hr; rt++, rf++)
  691.     {
  692.       for (cf = fm->lc, ct = to->lc; ct <= to->hc; ct++, cf++)
  693.     {
  694.       cpf = find_cell (rf, cf);
  695.       set_new_value (rt, ct, cpf ? GET_TYP (cpf) : 0, cpf ? &(cpf->c_z) : &dummy);
  696.  
  697.       if (cf == fm->hc)
  698.         cf = fm->lc - 1;
  699.     }
  700.       if (rf == fm->hr)
  701.     rf = fm->lr - 1;
  702.     }
  703. }
  704.  
  705. struct rng sort_rng;
  706. struct rng sort_ele;
  707. struct cmp *sort_keys;
  708. int sort_keys_alloc;
  709. int sort_keys_num = 0;
  710.  
  711. static int srdiff, erdiff, scdiff, ecdiff;
  712.  
  713. #ifdef TEST
  714. extern int debug;
  715. #endif
  716.  
  717. void
  718. sort_region ()
  719. {
  720.   srdiff = 1 + sort_rng.hr - sort_rng.lr;
  721.   erdiff = 1 + sort_ele.hr - sort_ele.lr;
  722.  
  723.   scdiff = 1 + sort_rng.hc - sort_rng.lc;
  724.   ecdiff = 1 + sort_ele.hc - sort_ele.lc;
  725.  
  726.   if (srdiff != erdiff && srdiff % erdiff != 0)
  727.     {
  728.       io_error_msg ("Rows %u:%u and %u:%u don't fit", sort_rng.lr, sort_rng.hr, sort_ele.lr, sort_ele.hr);
  729.       return;
  730.     }
  731.   if (scdiff != ecdiff && scdiff % ecdiff != 0)
  732.     {
  733.       io_error_msg ("Cols %u:%u and %u:%u don't fit", sort_rng.lc, sort_rng.hc, sort_ele.lc, sort_ele.hc);
  734.       return;
  735.     }
  736.   if (scdiff != ecdiff && srdiff != erdiff)
  737.     {
  738.       io_error_msg ("Can't sort this region!");
  739.       return;
  740.     }
  741.   modified = 1;
  742.   if (scdiff != ecdiff)
  743.     {
  744.       erdiff = 0;
  745.       sort (scdiff / ecdiff, cmp_cells, swp_cells, rot_cells);
  746.     }
  747.   else
  748.     {
  749.       ecdiff = 0;
  750.       sort (srdiff / erdiff, cmp_cells, swp_cells, rot_cells);
  751.     }
  752. }
  753.  
  754. extern int
  755. cmp_cells (n1, n2)
  756.      int n1;
  757.      int n2;
  758. {
  759.   CELL *c1, *c2;
  760.   int t1, t2;
  761.   union vals v1, v2;
  762.   CELLREF row1, row2, col1, col2;
  763.   int keyn;
  764.   int cmpval;
  765.  
  766.   if (n1 == n2)
  767.     return 0;
  768.  
  769.   for (keyn = 0; keyn < sort_keys_num; keyn++)
  770.     {
  771.       row1 = sort_rng.lr + (n1 * erdiff) + sort_keys[keyn].row;
  772.       col1 = sort_rng.lc + (n1 * ecdiff) + sort_keys[keyn].col;
  773.       row2 = sort_rng.lr + (n2 * erdiff) + sort_keys[keyn].row;
  774.       col2 = sort_rng.lc + (n2 * ecdiff) + sort_keys[keyn].col;
  775. #ifdef TEST
  776.       if (debug & 04)
  777.     io_error_msg ("Cmp %u %u  r%uc%u <-%u-> r%uc%u", n1, n2, row1, col1, sort_keys[keyn].mult, row2, col2);
  778. #endif
  779.       c1 = find_cell (row1, col1);
  780.       c2 = find_cell (row2, col2);
  781.       if (!c1 && !c2)
  782.     continue;
  783.  
  784.       if (c1)
  785.     {
  786.       t1 = GET_TYP (c1);
  787.       v1 = c1->c_z;
  788.     }
  789.       else
  790.     t1 = 0;
  791.       if (c2)
  792.     {
  793.       t2 = GET_TYP (c2);
  794.       v2 = c2->c_z;
  795.     }
  796.       else
  797.     t2 = 0;
  798.  
  799.       if (t1 == TYP_ERR || t1 == TYP_BOL)
  800.     {
  801.       t1 = TYP_STR;
  802.       v1.c_s = print_cell (c1);
  803.     }
  804.       if (t2 == TYP_ERR || t2 == TYP_BOL)
  805.     {
  806.       t2 = TYP_STR;
  807.       v2.c_s = print_cell (c2);
  808.     }
  809.       if (t1 != t2)
  810.     {
  811.       if (t1 == 0)
  812.         {
  813.           if (t2 == TYP_STR)
  814.         {
  815.           t1 = TYP_STR;
  816.           v1.c_s = "";
  817.         }
  818.           else if (t2 == TYP_INT)
  819.         {
  820.           t1 = TYP_INT;
  821.           v1.c_l = 0;
  822.         }
  823.           else
  824.         {
  825.           t1 = TYP_FLT;
  826.           v1.c_d = 0.0;
  827.         }
  828.         }
  829.       else if (t2 == 0)
  830.         {
  831.           if (t1 == TYP_STR)
  832.         {
  833.           t2 = TYP_STR;
  834.           v2.c_s = "";
  835.         }
  836.           else if (t1 == TYP_INT)
  837.         {
  838.           t2 = TYP_INT;
  839.           v2.c_l = 0;
  840.         }
  841.           else
  842.         {
  843.           t2 = TYP_FLT;
  844.           v2.c_d = 0.0;
  845.         }
  846.         }
  847.       else if (t1 == TYP_STR)
  848.         {
  849.           t2 = TYP_STR;
  850.           v2.c_s = print_cell (c2);
  851.         }
  852.       else if (t2 == TYP_STR)
  853.         {
  854.           t1 = TYP_STR;
  855.           v1.c_s = print_cell (c1);
  856.           /* If we get here, one is INT, and the other
  857.                is FLT  Make them both FLT */
  858.         }
  859.       else if (t1 == TYP_INT)
  860.         {
  861.           t1 = TYP_FLT;
  862.           v1.c_d = (double) v1.c_l;
  863.         }
  864.       else
  865.         {
  866.           t2 = TYP_FLT;
  867.           v2.c_d = (double) v2.c_l;
  868.         }
  869.     }
  870.       if (t1 == TYP_STR)
  871.     cmpval = strcmp (v1.c_s, v2.c_s);
  872.       else if (t1 == TYP_FLT)
  873.     cmpval = (v1.c_d < v2.c_d) ? -1 : ((v1.c_d > v2.c_d) ? 1 : 0);
  874.       else if (t1 == TYP_INT)
  875.     cmpval = (v1.c_l < v2.c_l) ? -1 : ((v1.c_l > v2.c_l) ? 1 : 0);
  876.       else
  877.     cmpval = 0;
  878.       if (cmpval)
  879.     return cmpval * sort_keys[keyn].mult;
  880.     }
  881.  
  882.   return 0;
  883. }
  884.  
  885. extern void
  886. swp_cells (n1, n2)
  887.      int n1;
  888.      int n2;
  889. {
  890.   int rn, cn;
  891.   CELLREF r1, r2, c1, c2;
  892.  
  893. #ifdef TEST
  894.   if (debug & 04)
  895.     io_error_msg ("Swap %u<-->%u", n1, n2);
  896. #endif
  897.   for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
  898.     for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
  899.       {
  900.     r1 = sort_rng.lr + (n1 * erdiff) + rn;
  901.     r2 = sort_rng.lr + (n2 * erdiff) + rn;
  902.     c1 = sort_rng.lc + (n1 * ecdiff) + cn;
  903.     c2 = sort_rng.lc + (n2 * ecdiff) + cn;
  904. #ifdef TEST
  905.     if (debug & 04)
  906.       io_error_msg ("Save  r%uc%u", r1, c1);
  907. #endif
  908.     move_cell (r1, c1, NON_ROW, NON_COL);
  909. #ifdef TEST
  910.     if (debug & 04)
  911.       io_error_msg ("Copy r%uc%u --> r%uc%u", r2, c2, r1, c1);
  912. #endif
  913.     move_cell (r2, c2, r1, c1);
  914.  
  915. #ifdef TEST
  916.     if (debug & 04)
  917.       io_error_msg ("Restore r%uc%u", r2, c2);
  918. #endif
  919.     move_cell (NON_ROW, NON_COL, r2, c2);
  920.  
  921.     /* push_cell(r1,c1);
  922.             push_cell(r2,c2); */
  923.       }
  924. }
  925.  
  926. extern void
  927. rot_cells (n1, n2)
  928.      int n1;
  929.      int n2;
  930. {
  931.   int rn, cn;
  932.   int nn;
  933.   CELLREF r1, r2, c1, c2;
  934.  
  935.   if (n1 + 1 == n2 || n2 + 1 == n1)
  936.     {
  937.       swp_cells (n1, n2);
  938.       return;
  939.     }
  940. #ifdef TEST
  941.   if (debug & 04)
  942.     io_error_msg ("Rot cells %u -- %u", n1, n2);
  943. #endif
  944.   for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
  945.     for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
  946.       {
  947.  
  948.     /* store a copy of cell # n2 */
  949.     r2 = sort_rng.lr + (n2 * erdiff) + rn;
  950.     c2 = sort_rng.lc + (n2 * ecdiff) + cn;
  951.     move_cell (r2, c2, NON_ROW, NON_COL);
  952.  
  953. #ifdef TEST
  954.     if (debug & 04)
  955.       io_error_msg ("Save r%uc%u", r2, c2);
  956. #endif
  957.     /* Copy each cell from n1 to n2-1 up one */
  958.     for (nn = n2; nn > n1; --nn)
  959.       {
  960.         r2 = sort_rng.lr + (nn * erdiff) + rn;
  961.         c2 = sort_rng.lc + (nn * ecdiff) + cn;
  962.  
  963.         r1 = sort_rng.lr + ((nn - 1) * erdiff) + rn;
  964.         c1 = sort_rng.lc + ((nn - 1) * ecdiff) + cn;
  965.  
  966.         move_cell (r1, c1, r2, c2);
  967. #ifdef TEST
  968.         if (debug & 04)
  969.           io_error_msg ("Copy r%uc%u --> r%uc%u", r1, c1, r2, c2);
  970. #endif
  971.         /* push_cell(r2,c2); */
  972.       }
  973.  
  974.     r1 = sort_rng.lr + (nn * erdiff) + rn;
  975.     c1 = sort_rng.lc + (nn * ecdiff) + cn;
  976. #ifdef TEST
  977.     if (debug & 04)
  978.       io_error_msg ("Restore r%uc%u", r1, c1);
  979. #endif
  980.     move_cell (NON_ROW, NON_COL, r1, c1);
  981.  
  982.     /* push_cell(r1,c1); */
  983.       }
  984. }
  985.  
  986. /* End of functions for sort_region() */
  987.